Introduction
Authentication mechanisms provide the core functionality to validate users credentials and authenticate them against a preconfigured Identity Store. They define the rules about security information, such as the format of how security information is stored in both credentials and tokens.
Each mechanism knows how to handle a specific org.picketbox.core.UserCredential type, from which all the necessary information will retrieved to proceed with the user authentication. During the authentication, the mechanisms are able to query the Identity Manager in order to retrieve and check the information for a specific user. In other words, check if the user is stored at a preconfigured Identity Store, validate his credentials and so forth.
Examples of mechanisms are username and password authentication, TOTP(Time-based One-time Password), certificate, digest, etc.
Overall Design
The contract for authentication mechanisms is defined by the org.picketbox.core.authentication.AuthenticationMechanism interface.
This interface defines some important methods as follow:
-
List<AuthenticationInfo> getAuthenticationInfo();
This method returns a list of org.picketbox.core.authentication.AuthenticationInfo. This class holds the information about the mechanism like which credentials type are supported, some description, etc. In other words, this method allows to described a specific mechanism.
-
AuthenticationResult authenticate(UserCredential credential);
This is the most important method when talking about authentication. The implementation defines the authentication logic and how the mechanism will handle the supported credentials to perform it.
You may noticed that this method returns a org.picketbox.core.authentication.AuthenticationResult type. This is the outcome for the authentication process, providing useful information like the authentication status, the user Principal, messages, etc.
The diagram bellow gives a overall sight about how the mechanisms are used during the authentication.
Basically, the authentication takes a few steps:
-
The PicketBoxManager receives a authentication request for a specific UserContext instance. This instance is already setup with a UserCredential.
-
The manager retrieves all supported/registered authentication mechanisms. For each mechanisms, the manager checks if the provided UserCredential type is supported.
-
If the mechanism supports a specific credential type it tries to validate it and return a AuthenticationResult instace populated with the user principal, authentication status, messages, etc. At this point the Identity Manager is used to query user information, validate credentials, etc.
-
The PicketBoxManager uses the result to continue (or not) with the user authentication.
Authentication Result
The org.picketbox.core.authentication.AuthenticationResult holds information about the authentication performed by a mechanism. These information are important to let you know what was done by the mechanism, allowing to take decisions around the authentication process.
Mechanisms should use the AuthenticationResult to provide the following information:
-
User java.security.Principal
The principal represents any entity, such as an individual, a corporation, and a login id. Mechanisms should always map an user to a java.security.Principal, if the authentication was successful.
-
Status
The status information tells the current status of the authentication process as org.picketbox.core.authentication.AuthenticationStatus. Examples of status are: SUCCESS, FAILED, INVALID_CREDENTIALS, CONTINUE, etc.
If the mechanism provide a chalenge/response authentication, the status information helps to tell clients if the authentication was successful or if it need more steps to be done.
The AuthenticationResult is always populated into the UserContext after the authentication.
Example
The code above shows how a authentication mechanism looks like. It shows the code for a simple mechanism that performs an Username and Password based authentication.
public class UserNamePasswordAuthenticationMechanism extends AbstractAuthenticationMechanism {
@Override
public List<AuthenticationInfo> getAuthenticationInfo() {
List<AuthenticationInfo> arrayList = new ArrayList<AuthenticationInfo>();
arrayList.add(new AuthenticationInfo("Username and Password authentication service.",
"A simple authentication service using a username and password as credentials.",
UsernamePasswordCredential.class));
return arrayList;
}
@Override
protected Principal doAuthenticate(UserCredential credential, AuthenticationResult result) throws AuthenticationException {
UsernamePasswordCredential userCredential = (UsernamePasswordCredential) credential;
// try to retrieve the user from the configured identity store
User user = getIdentityManager().getUser(userCredential.getUserName());
if (user != null && getIdentityManager().validateCredential(user, userCredential.getCredential())) {
return new PicketBoxPrincipal(user.getId());
}
return null;
}
}
The class above is not implementing directly the org.picketbox.core.authentication.AuthenticationMechanism interface. Instead of that, it is using a base class provided by PicketBox: org.picketbox.core.authentication.impl.AbstractAuthenticationMechanism.
Configuration
PicketBox already provides some built-in implementations. That means you don't need to provide any additional configuration if you are going to use one of these built-in mechanisms.
But if you want to provide your own authentication mechanism implementation you just need to build PicketBox configuration as following:
ConfigurationBuilder builder = new ConfigurationBuilder();
CustomAuthenticationMechanism customMechanism = new CustomAuthenticationMechanism();
// register the custom authentication mechanism
builder.authentication().mechanism(customMechanism);
// build the configuration and create/start the manager